package com.eryos.gwt.estate.client;

import com.allen_sauer.gwt.log.client.Log;
import com.eryos.gwt.estate.client.factory.ClientFactory;
import com.eryos.gwt.estate.client.mvp.AppActivityMapper;
import com.eryos.gwt.estate.client.mvp.AppPlaceHistoryMapper;
import com.eryos.gwt.estate.client.mvp.CustomAsyncCallback;
import com.eryos.gwt.estate.client.place.HomePlace;
import com.google.gwt.activity.shared.ActivityManager;
import com.google.gwt.activity.shared.ActivityMapper;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.place.shared.Place;
import com.google.gwt.place.shared.PlaceController;
import com.google.gwt.place.shared.PlaceHistoryHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.web.bindery.event.shared.EventBus;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 * 
 * @author combeol
 * @version $Revision$
 */
public class Estate implements EntryPoint {

    private ClientFactory clientFactory;

    // Define the default place
    private final Place defaultPlace = new HomePlace("Home");
    private final SimplePanel mainPanel = new SimplePanel();

    /**
     * Note, we defer all application initialization code to {@link #onModuleLoad2()} so that the
     * UncaughtExceptionHandler can catch any unexpected exceptions.
     */
    @Override
    public void onModuleLoad() {
        /*
         * Install an UncaughtExceptionHandler which will produce <code>FATAL</code> log messages
         */
        Log.setUncaughtExceptionHandler();

        // use deferred command to catch initialization exceptions in onModuleLoad2
        Scheduler.get().scheduleDeferred(new ScheduledCommand() {
            @Override
            public void execute() {
                onModuleLoadMVPDeferred();
            }
        });
    }

    /**
     * 
     */
    public void onModuleLoadMVPDeferred() {
        Log.info("onModuleLoadMVPDeferred");

        // Create ClientFactory using deferred binding so we can replace with different
        // impls in gwt.xml
        Log.info("Init ClientFactory, EventBus and PlaceController");
        clientFactory = GWT.create(ClientFactory.class);
        EventBus eventBus = clientFactory.getEventBus();
        PlaceController placeController = clientFactory.getPlaceController();

        /**
         * The ActivityManager keeps track of all Activities running within the context of one container widget. It
         * listens for PlaceChangeRequestEvents and notifies the current activity when a new Place has been
         * requested. If the current Activity allows the Place change (Activity.onMayStop() returns null) or the user
         * allows it (by clicking OK in the confirmation dialog), the ActivityManager discards the current Activity
         * and starts the new one. In order to find the new one, it uses your app's ActivityMapper to obtain the
         * Activity associated with the requested Place.
         */
        // Start ActivityManager for the main widget with our ActivityMapper
        Log.info("Init ActivityMapper and ActivityManager");
        ActivityMapper activityMapper = new AppActivityMapper(clientFactory);
        ActivityManager activityManager = new ActivityManager(activityMapper, eventBus);
        activityManager.setDisplay(mainPanel);

        // Start PlaceHistoryHandler with our PlaceHistoryMapper
        Log.info("Init PlaceHistoryMapper and PlaceHistoryHandler");
        AppPlaceHistoryMapper historyMapper = GWT.create(AppPlaceHistoryMapper.class);
        PlaceHistoryHandler historyHandler = new PlaceHistoryHandler(historyMapper);
        historyHandler.register(placeController, eventBus, defaultPlace);

        Log.info("Set default panel");
        Log.debug("Remove content");
        RootPanel.get("content").clear();
        clear(RootPanel.get("content").getElement());
        Log.debug("Add new content");
        RootPanel.get("content").add(mainPanel);

        // Goes to the place represented on URL else default place
        Log.info("Start history handler");
        historyHandler.handleCurrentHistory();

        // Display footer with Application version
        Log.info("Load application information (footer)");
        loadApplicationInformation();
    }

    /**
     * Clear (HTML and Widget) a DOM element.
     * 
     * @param parent
     *            to clean
     */
    public void clear(Element parent) {
        Element firstChild;
        while ((firstChild = DOM.getFirstChild(parent)) != null) {
            DOM.removeChild(parent, firstChild);
        }
    }

    /**
     * Show application information in the footer.
     */
    private void loadApplicationInformation() {

        clientFactory.getConfigService().getApplicationVersion(new CustomAsyncCallback<String>() {
            @Override
            public void onSuccess(final String result) {
                RootPanel.get("footer").add(new Label(result));
            }
        });

    }
}
